// 消息
class Message {
  // 获取进入方向
  static getEntryDirection (arg) {
    let {from, to} = arg
    if (from === 'right' && to === 'left') {
      return 'left'
    } else if (from === 'left' && to === 'right') {
      return 'right'
    } else {
      return 'right'
    }
  }
  constructor (arg) {
    // 运动方向
    this.direction = arg.direction
    // 进入方向 left or right
    this.entryDirection = Message.getEntryDirection(arg.direction)
    // 靠顶还是靠底
    this.entryEdge = arg.entryEdge
    // 当前位置
    this.position = arg.w
    // 速度（px）
    this.speed = 2
    // 当前元素
    this.el = null
    // 创建当前元素
    this.creat(arg)
  }
  // 创建
  creat(arg) {
    let el = document.createElement('div')
    el.classList.add('message-el')
    el.classList.add(`message-el-${this.direction.from}-${this.direction.to}`)
    el.classList.add(`message-el-${this.entryEdge}`)
    el.innerText = arg.text
    el.style[this.entryDirection] = this.position + 'px'
    if (arg.style) {
      Object.keys(arg.style).forEach(item => el.style[item] = arg.style[item])
    }
    this.el = el
  }
  // 移动
  move() {
    this.position -= this.speed
    this.el.style[this.entryDirection] = this.position + 'px'
  }
  // 设置元素垂直距离
  setVerticalDistance(number) {
    this.el.style[this.entryEdge] = number + 'px'
  }
  // 删除
  remove() {}
}

// 行
class Row {
  constructor () {
    // 元素列表
    this.list = []
  }
  // 添加元素
  add(el) {
    this.list.push(el)
  }
  // 移除元素
  remove(index) {
    this.list.splice(index, 1)
  }
  // 最大距离（该行所有元素中距离出去一侧最大的元素的距离 + 本身宽度）
  maxDistance() {
    // 目前只考虑最后一个元素
    let el = this.list[this.list.length - 1]
    return el.position + el.el.offsetWidth
  }
}

// 集合
class BulletChat {
  constructor (arg) {
    // 容器
    this.container = document.querySelector(arg.el)
    // 帧率
    this.frameRate = 1000 / 60
    // 定义的文本行高
    this.lineHeight = 24
    // 实际单行高度（计算取得）
    this.rowHeight = 24
    // 行数（决定了能展示多少行）
    this.rowSize = 0
    // 显示区域（弹幕占屏幕的几分之几）
    this.displayArea = arg.displayArea || 0.25
    // 元素集合
    this.list = []
    // 等待追加元素集合
    this.waitList = []
    // 运动方向
    this.direction = arg.direction || {from: 'right', to: 'left'} 
    // 靠顶还是靠底
    this.entryEdge = arg.entryEdge || 'top' 
    // 消息最小间隔
    this.interval = 10
    // 定时器
    this.timer = null
    // 移除距离（元素位置小于多少时移除）
    this.removeDistance = -20
    this.init()
  }
  // 初始化
  init() {
    this.countRows()
  }
  // 开始
  play() {
    if (this.timer) return
    this.timer = setInterval(() => {
      let listRemoves = []
      // 移动元素
      this.list.forEach((item, index) => {
        item.list.forEach((rowItem, rowIndex) => {
          rowItem.move()
          // 计算是否超出隐藏，是则删除改消息元素
          if (rowItem.position + rowItem.el.offsetWidth < this.removeDistance) {
            listRemoves.push([index, rowIndex].join('-'))
          }
        })
      })
      // 处理带删除的元素
      if (listRemoves.length) {
        this.list.forEach((item, index) => {
          item.list = item.list.filter((rowItem, rowIndex) => {
            let whetherRemove = _.indexOf(listRemoves, [index, rowIndex].join('-')) === -1
            if (!whetherRemove) {
              this.container.removeChild(rowItem.el)
            }
            return whetherRemove
          })
        })
      }
      // 添加新的元素
      this.distributeWaitEl()
    }, this.frameRate)
  }
  // 暂停
  pause() {
    if (!this.timer) return
    clearInterval(this.timer)
    this.timer = null
  }
  // 追加（追加元素至待分发列表）
  add(arg) {
    // 创建消息元素
    let messageEl = new Message({ 
      w: this.container.offsetWidth,
      text: arg.text,
      style: arg.style,
      direction: this.direction,
      entryEdge: this.entryEdge
    })
    this.waitList.push(messageEl)
  }
  // 分发等待元素集合
  distributeWaitEl() {  
    // 遍历所有的行看是否有位置可以分发
    for (let i = 0; i < this.rowSize; i++) {
      if (!this.waitList.length) return
      let item = this.list[i]
      if (!item.list.length) {
        this.determineDistribute(item, i) 
        continue
      }
      let distance = item.maxDistance() + this.interval
      if (distance < this.container.offsetWidth) {
        this.determineDistribute(item, i)
      }     
    }
  }
  // 确定分发元素
  determineDistribute(item, index) {
    let messageEl = this.waitList.shift()
    messageEl.setVerticalDistance(index * this.rowHeight)
    item.add(messageEl)
    this.container.appendChild(messageEl.el)
  }
  // 删除
  remove() {}
  // 清空所有元素重构面板
  refactoringPanel(arg = {}) {
    // 先暂停停止做一些不必要的运算
    this.pause()
    this.list.forEach((item, index) => {
      item.list = []
    })
    this.waitList = []
    this.container.innerHTML = ''
    Object.keys(arg).forEach((item) => {  
      this[item] = arg[item]
    })
    this.countRows()
    this.play()
  }
  // 容器大小变化
  resize() {
    this.countRows()
  }
  // 更新行数并动态添加（行够则不要添加）
  countRows() {
    let height = this.container.offsetHeight * this.displayArea
    // 取整行数
    let rowSize = Math.floor(height  / this.lineHeight)
    // 剩余距离行数平分间隔
    let supplement = (height - rowSize * this.lineHeight) / rowSize
    this.rowHeight = this.lineHeight + supplement
    this.rowSize = rowSize
    for (let i = 0; i < this.rowSize; i++) {
      if (!this.list[i]) {
        this.list[i] = new Row()
      }
    }
  }
}